#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#include "SList.h"

// head表示链表，  *head是操作链表(链表的首地址或者链表的首节点)， **head是操作链表的第一个节点(即第一个元素的节点的地址)

//构造新节点(需要插入的节点和数)
Node* NewSListNode(DataType data)
{
    Node* node = (Node*)malloc(sizeof(Node)); //开辟Node结构体的大小
    if(NULL == node) //不能用assert
    {
        exit(0);
        return NULL;
    }

    node->data = data;
    node->next = NULL; //并不知道下一个节点是谁，给成空

    return node;
}

//初始化
//在函数操作中，如果需要修改head的指向，必须传递二级指针。**head就是第一个元素的节点的地址
void SListInit(Node** head)
{
    assert(head);
    *head = NULL;
}

//尾插
void SListPushBack(Node** head, DataType data)
{
    assert(head); 

    //1.当链表为空链表
    if(NULL == *head)
    {
        *head = NewSListNode(data); //构造一个新的链表
    }
    else
    {
        //2.当链表非空
        //2.1 找到链表中的最后一个节点
        Node* cur = *head;
        while(cur->next)  //当cur->next == NULL,则cur是最后一个节点
        {
            cur = cur->next;
        }
        
        cur->next = NewSListNode(data);
    }
}

//尾删
void SListPopBack(Node** head)
{
    assert(head);

    if(NULL == *head)   //空链表，什么都没有
        return;
    else if(NULL == (*head)->next)  //链表中只有一个节点
    {
        free(*head);
        *head = NULL;
    }
    else  //链表中有多个节点 
    {
        //找到链表中最后一个节点，并保存其前一个节点，让其的下一个节点指向空
        Node* cur = *head;
        Node* pre = NULL; //用来保存最后一个节点的前一个节点
        while(cur->next)
        {
            pre = cur; //pre是cur的前一个节点
            cur = cur->next; //cur是最后一个节点
        }

        free(cur); // 释放掉最后一个节点
        pre->next = NULL; //让pre的下一个节点指向空
    }
}

//头插
void SListPushFront(Node** head, DataType data)
{
    assert(head);

    Node* newNode = NewSListNode(data);

    newNode->next = *head;  //第一步:让新节点的下一个节点指向第一个元素的节点
    *head = newNode;  //第二步：让新的节点成为第一个节点
    
}

//头删
void SListPopFront(Node** head)
{
    
    Node* delNode = NULL; //声明变量delNode，不声明会出错
    
    assert(head);

    if(NULL == *head)
        return;
    
    delNode = *head; //先把第一个节点标记出来
    *head = delNode->next; //让下一个节点成为第一个节点
    free(delNode); //释放第一个元素的节点
}

//任意位置的插入,注意：只能往pos位置的后面插入，不能在pos位置之前插入，因为pos位置之前的节点并不知道
//如果要插入到pos之前，在执行上面的操作之后，只需交换两个节点的值域就可以
void SListInsert(Node* pos, DataType data)
{
    Node* newNode = NULL;
    if(NULL == pos)
        return;

    newNode = NewSListNode(data);
    newNode->next = pos->next;
    pos->next = newNode;
}

//任意位置的删除，只能删除pos位置之后的一个节点
//如果pos位置删除之后，就无法链接前面的节点
void SListErase(Node* pos)
{
    Node* delNode = NULL;
    if(NULL == pos || NULL == pos->next)
        return;

    delNode = pos->next;
    pos->next = pos->next->next;
    free(delNode);
}

//获取有效元素的大小
int SListSize(Node* head)
{
    int count = 0;
    Node* cur = head;
    while(cur)
    {
        ++count;
        cur = cur->next;
    }
    return count;
}

//查找
Node* SListFind(Node* head, DataType data)
{
    Node* cur  = head;
    while(cur)
    {
        if(data == cur->data)
            return cur;

        cur = cur->next;
    }
    return NULL; //没有找到这个节点，则返回空
}

//销毁，采用头删法进行销毁
void SListDestroy(Node** head)
{
    Node* delNode = NULL;
    assert(head);
    while(NULL != *head)
    {
        delNode = *head;
        free(delNode); 
        *head = delNode->next;
    }
}

//测试
void SListPrint(Node* head)
{
    Node* cur = head;
    while(cur)
    {
        printf("%d--->",cur->data);
        cur = cur->next;
    }

    printf("NULL\n");
}

